﻿using System.Runtime.Serialization;
using System.Collections.Generic;
using System.Linq;

namespace ScrumFactory
{

    public enum BacklogItemStatus : short {
        ITEM_REQUIRED,
        ITEM_WORKING,
        ITEM_DONE,
        ITEM_CANCELED
    }

    [DataContract]
    public class BacklogItem
    {

        private short status;
        

        [DataMember]
        public string BacklogItemUId { get; set; }

        [DataMember]
        public short BacklogItemNumber { get; set; }

        [DataMember]
        public string ProjectUId { get; set; }

        [DataMember]
        public string Name { get; set; }
        
        [DataMember]
        public string Description { get; set; }
        
        

        [DataMember]
        public System.DateTime CreateDate { get; set; }

        [DataMember]
        public List<PlannedHour> PlannedHours {
            get;
            set;
        }

        [DataMember]
        public short Status {
            get {
                return status;
            }
            set {
                status = value;
                if (status == (short) BacklogItemStatus.ITEM_WORKING) {
                    if(StartedAt==null)
                        StartedAt = System.DateTime.Now;
                    FinishedAt = null;
                }
                if (status == (short)BacklogItemStatus.ITEM_DONE || status == (short)BacklogItemStatus.ITEM_CANCELED) {
                    if(FinishedAt==null)
                        FinishedAt = System.DateTime.Now;                    
                }
                if (status == (short)BacklogItemStatus.ITEM_REQUIRED) {
                    StartedAt = null;
                    FinishedAt = null;
                }
            }
        }

        [DataMember]
        public System.DateTime? StartedAt { get; set; }

        [DataMember]
        public System.DateTime? FinishedAt { get; set; }

        public Project Project { get; set; }


        /// <summary>
        /// Gets the planned hours for ths item at a given planning.
        /// </summary>
        /// <remarks>If there is no hours planned at the planning number, returns the last planning.</remarks>
        /// <param name="planningNumber">The planning number.</param>
        /// <returns>The planned hours</returns>
        public List<PlannedHour> GetPlannedHoursAtPlanning(int planningNumber) {
            if (PlannedHours == null)
                return null;
            
            if(planningNumber > LastPlanningNumber)
                return PlannedHours.Where(p => p.PlanningNumber == LastPlanningNumber).ToList();

            return PlannedHours.Where(p => p.PlanningNumber == planningNumber).ToList();
        }

        public int LastPlanningNumber {
            get {
                if (PlannedHours == null || PlannedHours.Count==0)
                    return -1;
                return PlannedHours.Max(p => p.PlanningNumber);
            }
        }

        /// <summary>
        /// Gets the total hours for this item at a given planning.
        /// </summary>
        /// <param name="planningNumber">The planning number.</param>
        /// <returns>The sum of hours at the planning</returns>
        public decimal GetTotalHoursAtPlanning(int planningNumber) {
            List<PlannedHour> hours = GetPlannedHoursAtPlanning(planningNumber);
            if (hours == null)
                return 0;
            decimal? total = hours.Sum(p => p.Hours);
            if (total == null)
                return 0;
            return (decimal)total;            
        }




        /// <summary>
        /// Gets the current planned hours for this item.
        /// </summary>
        /// <value>The current planned hours.</value>
        public List<PlannedHour> CurrentPlannedHours {
            get {
                int currentPlanNumber = PlannedHours.Max(p =>p .PlanningNumber);
                return GetPlannedHoursAtPlanning(currentPlanNumber);
            }
        }

        /// <summary>
        /// Gets the total amount of hours current planned for this item.
        /// </summary>
        public decimal CurrentTotalHours {            
            get {
                if (CurrentPlannedHours == null)
                    return 0;      
                decimal? total = CurrentPlannedHours.Sum(p =>p.Hours);
                if (total == null)
                    return 0;
                return (decimal) total;                
            }
        }

      

        /// <summary>
        /// Gets the current planning number of this item.
        /// </summary>
        public int PlanningNumber {
            get {
                if (PlannedHours == null || PlannedHours.Count == 0)
                    return 0;
                return PlannedHours[0].PlanningNumber;
            }
        }


        /// <summary>
        /// Gets or sets the sprint number.
        /// </summary>
        /// <value>The sprint number.</value>
        public int? SprintNumber {
            get {
                if (PlannedHours == null || PlannedHours.Count==0)
                    return null;                
                return PlannedHours[0].SprintNumber;
            }
            set {
                foreach (PlannedHour h in PlannedHours)
                    h.SprintNumber = value;
            }
        }

      

        /// <summary>
        /// Sync the planned hours collection of the item with the roles of the project.
        /// </summary>
        /// 
        public void SyncPlannedHoursAndRoles() {
           
            if (Project == null)
                return;
            if (Project.Roles == null)
                return;
            
            if (PlannedHours == null)
                PlannedHours = new List<PlannedHour>();

            foreach (Role r in Project.Roles) {
                PlannedHour hour = PlannedHours.SingleOrDefault(h => h.RoleUId == r.RoleUId);
                if (hour == null) {
                    PlannedHours.Add(new PlannedHour() {
                        Role = r,
                        RoleUId = r.RoleUId,
                        PlanningNumber = Project.CurrentPlanningNumber,
                        SprintNumber = Project.CurrentValidSprint.SprintNumber,
                        BacklogItemUId = this.BacklogItemUId,
                        Hours = 0
                    });
                } else {
                    hour.Role = r;
                }
            }

            PlannedHour[] deletedHours = PlannedHours.Where(h => !Project.Roles.Any(r => r.RoleUId == h.RoleUId)).ToArray();
            for (int i = deletedHours.Length - 1; i >= 0; i--)
                PlannedHours.Remove(deletedHours[i]);


            
        }

    }

    [DataContract]    
    public class PlannedHour {


        [DataMember]
        public Role Role { get; set; }

        [DataMember]
        public string RoleUId { get; set; }

        [DataMember]
        public string BacklogItemUId { get; set; }

        [DataMember]
        public int PlanningNumber { get; set; }

        [DataMember]
        public int? SprintNumber { get; set; }

        [DataMember]
        public decimal? Hours { get; set; }
    }
}
